#ifndef __COORDINATOR__
#define __COORDINATOR__

#include <QObject>
#include <QDate>

#include "common.h"
class QMqttClient;
class QThread;
class QTimer;

class MqttClient;
class UIController;
class UIWidgetController;
class PrtController;
class NCController;
class CntlBoardController;
class PaperController;
class DataStorage;
class HttpCloud;
class FingerPrintController;
class SurveillanceController;

class Coordinator : public QObject
{
	Q_OBJECT

public:

	Coordinator(QObject *parent = nullptr);
	~Coordinator();

public:

	enum DEVICE_STATUS {
		DEV_NORMAL,
		DEV_SENSOR_ERROR,
		DEV_OTHER_ERROR
	};
	enum DEVICE_STATE {
		DEV_IN_IDLE,
		DEV_IN_DEPOSTING,
		DEV_IN_CLEARING,
		DEV_IN_SERVICING
	};
	enum {
		BAG_EMPTY,
		BAG_NEARLY_EMPTY,
		BAG_NEARLY_FULL,
		BAG_FULL
    };
	struct DeviceStatus {
		QString terminal_id;
		uint32_t dev_status;
		uint32_t state;
		uint32_t bag_status;
		uint32_t note_amount;
		uint32_t note_count;
		uint32_t coin_amount;
		uint32_t coin_count;
	};
	typedef struct DeviceStatus DeviceStatus;

public:

	QString get_vendor_name() { return m_vendor_name; }
	QString get_client_name() { return m_client_name; }
	QString get_terminal_name() { return m_terminal_name; }
	QString get_terminal_id() { return m_terminal_id; }
	QString get_user_name() { return m_user_name; }

	DeviceStatus get_dev_status() { return m_dev_status; }

	bool nc_in_operation();

    uint32_t category_count() { return m_category_list.count(); };
    uint32_t category_code(uint32_t idx) {
        if (idx < (uint32_t) m_category_list.count())
			return m_category_list[idx].category_code;
		return 0x10;
	};
	QString category_description(uint32_t idx) {
        if (idx < (uint32_t) m_category_list.count())
			return m_category_list[idx].category_desc;
		return "";
	};

	TransInfo get_current_trans() { return m_curr_trans; };
	TransInfo get_last_saved_trans() { return m_last_saved_trans; };
	TransInfo get_last_subtrans() { return m_last_subtrans; };

	bool get_auto_count() { return m_nc_auto_count; };
	bool get_auto_store() { return m_nc_auto_store; };
	bool get_use_amount_limit() { return m_use_amount_limit; };
	bool get_account_failed_trans() { return m_account_failed_trans; };
	uint32_t get_curr_amount_limit() { return m_curr_amount_limit; };
	uint32_t get_max_amount_limit() { return m_max_amount_limit; };

	void set_auto_count(bool on);
	void set_auto_store(bool on);
	void set_use_amount_limit(bool on);
	void set_account_failed_trans(bool on);

	PaperController *get_paper_controller() { return m_paper_controller; };

signals:

	void prt_state_changed(bool online);
	void notecounter_state_changed(bool online);
	void server_state_changed(bool online);
	void bag_state_changed(bool online);
	void case_door_state_changed(bool online);

	void admin_logged();
	void user_logged();
	void display_note(NoteInfo note_info);
	void store_note_complete();
	void store_coin_complete();
	void store_fail();
	void data_show(QStringList s_list);
	void op_data_show(QStringList s_list);
	void clr_data_show(QStringList s_list);
	void clr_total_show(ClearInfo clr_info);
    void do_edit_op(QString op_name, QString op_password, QString terminal_name, uint32_t op_finger_id);

	void fp_detect_start();
	void fp_detect_stop();
	void fp_enroll_start();
	void fp_save(uint32_t finger_id);
	void fp_delete(uint32_t finger_id);

	void clear_transaction();
    void start_store();
    void complete_store();
    void start_coin_transaction();
    void complete_coin_transaction();
    void inquiry_nc_status();

    void auto_countinue_count();
    void auto_store();

	void set_mode(unsigned int mode);
	void start_count();

	void print(TransInfo trans_info);
	void print_all(QList<TransInfo> trans_list);
	void clr_print(ClearInfo clr_info);

	void open_shell();
	void close_shell();
	void open_store_gate();
	void close_store_gate();
	void turn_on_fans();
	void turn_off_fans();
	void takeout_paper();
	void prepare_store();
	void store_paper();

	void paper_action(uint8_t act);

    void count_starting();
    void count_completing();
    void store_starting();
    void store_completing();

    void set_user_name(QString name);
    void set_machine_info(QString name, QString server_name, QString terminal_id);

    void upload_transaction(TransInfo trans_info);

	void msg_report(uint32_t msg_type, uint32_t msg_id);
	void msg_report(QString msg);
	void set_nc_fault_prompt(uint16_t error1, uint16_t error2);

	void start_video_record();
	void stop_video_record();

private slots:

	void start_work();

	void component_check();
	void task_check();
	void task_upload();
	void update_component_status();

    void enter_screen(uint32_t scrn_id);

	void enter_init_mode();
	void enter_intelligent_mode();
	void enter_mixed_mode();
	void enter_count_mode();
	void enter_note_transaction_mode();
	void enter_coin_transaction_mode();
	void countinue_count();
	void count_exception(uint16_t cmd, uint16_t exception_code, QString exception_name);
	void count_started();
	void count_complete(uint16_t status);

	void user_login(QString user_name, QString password);
	void user_logout();
	void user_modify_password(QString user_name, QString old_password, QString new_password);

	void transaction_count_info(NoteInfo note_info);
	void print_coin_trans();
	void store_note();
	void store_coin();
	void store_in_progress();
	void store_exception(uint16_t cmd, uint16_t exception_code, QString exception_name);
	void store_complete(uint16_t status);
	void finish_transaction(uint8_t store_cmd = 0, uint8_t store_exception = 0);
	void inquiry_data(QDate start_date, QDate stop_date);
    void inquiry_op();

	void add_op(QString user_name, QString user_password, QString station_id);
	void update_op(QString user_name, QString user_password, QString station_id, uint32_t finger_id);
	void delete_op(uint32_t user_idx);
    void edit_op(uint32_t user_idx);
	void fp_dected(int id);
	void fp_enroll(QString user_name);
	void fp_message(uint32_t proc, uint32_t enroll_step);

	void print_current_transaction();
    void print_transaction(uint32_t rec_idx);
    void print_transactions();

	void nc_error(uint16_t error1, uint16_t error2);
	void nc_status(uint16_t status);

    void store_gate_status(uint16_t status);

    void machine_info(QString name, QString server_name, QString terminal_id);
	void inquiry_clr_data(QDate start_date, QDate stop_date);
    void print_clr_transaction(unsigned int rec_idx);

    void start_clear_deposit();
    void clear_deposit();

    void transaction_uploaded(TransInfo trans_info);

	void sw_upgrade(QString link, QString file_name, QString new_version);

private:

	uint32_t gpio_get(QString dev_name);
	uint32_t save_transaction(uint32_t trans_type);
	void save_failed_transaction(uint32_t trans_type);
	void update_transaction_summary();

private:

	enum TaskType {
		TASK_NONE,
		TASK_OPEN_BAG_GATE,
		TASK_CLOSE_BAG_GATE,
		TASK_STORE_NOTE,
		TASK_STORE_COIN,
		TASK_COUNT
	};
	struct Task {
		enum TaskType curr_task;
		enum TaskType next_task;
		uint32_t waiting_time;
		bool store_completed;
		uint8_t store_cmd;
		uint8_t store_exception;
		bool count_started;
		bool count_completed;
		uint8_t count_exception;
		uint32_t inquiry_count;
	};
	typedef struct Task Task;
	struct CategoryDef {
		uint32_t category_code;
		QString category_desc;
	};
	typedef struct CategoryDef CategoryDef;

private:

	void set_task(TaskType curr, TaskType next, uint32_t timeout);
	void fp_cleanup();

private:

	MqttClient *m_client;
	UIController *m_ui_controller;
	UIWidgetController *m_widgets;
	PrtController *m_prt_controller;
	NCController *m_notecounter_controller;
	CntlBoardController *m_cntlbrd_controller;
	PaperController *m_paper_controller;
	DataStorage *m_datastorage;
	HttpCloud *m_http_server;
	FingerPrintController *m_fp_controller;
	SurveillanceController *m_surveillance_controller;

	QString m_vendor_name;
	QString m_client_name;
	QString m_terminal_name;
	QString m_terminal_id;
	QString m_user_name;
	QString m_user_password;
	bool m_use_amount_limit;
	uint32_t m_curr_amount_limit, m_max_amount_limit;
	bool m_account_failed_trans;
	DeviceStatus m_dev_status;

	QString m_http_server_name;

	QList<CategoryDef> m_category_list;
	TransInfo m_accumulated_trans;
	TransInfo m_curr_trans;
	TransInfo m_last_saved_trans;
	TransInfo m_last_subtrans;
	Task m_task;

	QTimer *m_component_check_timer;
	QTimer *m_task_timer;
	QTimer *m_upload_timer;

	bool m_user_logged;
	bool m_bag_gate_opened;
	bool m_server_online;
	bool m_prt_online;
	bool m_notecounter_online;

	bool m_case_door_closed;
	bool m_sensor1_no_note;
	bool m_sensor2_no_note;

	bool m_nc_auto_count;
	bool m_nc_auto_store;
	bool m_nc_fault;

	uint32_t m_stop_inquiry_countdown;

	QString m_case_door_gpio_name;
	QString m_note_sensor1_gpio_name;
	QString m_note_sensor2_gpio_name;

public:

	static Coordinator *coordinator() {
		return s_coordinator;
	}

private:

	static Coordinator *s_coordinator;
};

#endif
